
package services;

import dao.ContestJpaController;
import dao.exceptions.NonexistentEntityException;
import entities.Contest;
import entities.Problem;
import entities.User;
import exceptions.DatabaseException;
import exceptions.NonExistentObjectException;
import exceptions.PreexistingObjectException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import util.EnumSearchParameter;
import vo.VOContest;
import vo.VOScoreboard;
import vo.VOUser;

/**
  * @author sbaldrich
 */
public class ContestService
{
    private static HashMap scoreboards;
    private static HashMap getScoreboards()
    {
        if(scoreboards == null)
            scoreboards = new HashMap <String , HashMap<String , VOScoreboard> >();
        return scoreboards;
    }


    private static ContestJpaController cc;
    public static ContestJpaController getInstance()
    {
        if(cc == null)
            cc = new ContestJpaController();
        return cc;
    }

    private static UserService us;
    private static UserService getUserService()
    {
        if(us == null)
            us = new UserService();
        return us;
    }

    private static SubmissionService ss;
    private static SubmissionService getSubmissionService()
    {
        if(ss == null)
            ss = new SubmissionService();
        return ss;
    }

    private static ProblemService ps;
    private static ProblemService getProblemService()
    {
        if(ps == null)
            ps = new ProblemService();
        return ps;
    }

    public void save(VOContest vo) throws Exception
    {
        cc = getInstance();
        if(find(vo.getContestCode())!=null)
            throw new PreexistingObjectException("Contest Code");
        Contest u = new Contest(vo);
        try
        {
            cc.create(u);
        } catch (Exception e)
        {
            throw new DatabaseException();
        }
    }

    public VOContest find(String contestCode)throws Exception
    {
        cc = getInstance();
        try
        {
            return cc.findContest(contestCode).getVO();
        } catch (Exception e)
        {
            throw e;
        }
    }
    public Contest findObject(String contestCode)throws Exception
    {
        cc = getInstance();
        try
        {
            return cc.findContest(contestCode);
        } catch (Exception e)
        {
            throw e;
        }
    }

    public void update(VOContest vo)throws Exception
    {
        cc = getInstance();
        Contest c;
        try
        {
            c = new Contest(vo);
            cc.edit(c);
        } catch (Exception e)
        {
            if(e instanceof NonexistentEntityException)
            {
                throw new NonExistentObjectException();
            }
            throw new DatabaseException("ContestService.update Operation");
        }
    }

    public void updateObject(Contest c)throws Exception
    {
        cc = getInstance();
        try
        {
            cc.edit(c);
        } catch (Exception e)
        {
            if(e instanceof NonexistentEntityException)
            {
                throw new NonExistentObjectException();
            }
            throw new DatabaseException("ContestService.update Operation");
        }
    }

    public void delete(VOContest vo)throws Exception
    {
        cc = getInstance();
        try
        {
            cc.destroy(vo.getIdContest());
        } catch (Exception e)
        {
            if( e instanceof NonexistentEntityException)
            {
                throw new NonExistentObjectException();
            }
            throw new DatabaseException("ContestService.delete Operation");
        }
    }

    public void addUser(String contestCode, String handle) throws Exception
    {
        us = getUserService();
        try
        {
            User u = us.findObject(handle);
            Contest c = findObject(contestCode);
            if(u == null)
                throw new NonExistentObjectException("User");
            if(c == null)
                throw new NonExistentObjectException("Contest");
            u.getContestList().add(c);
            c.getUserList().add(u);
            us.updateObject(u);
            updateObject(c);
        }
        catch (Exception e)
        {
            throw e;
        }
    }

    public ArrayList<VOScoreboard> getScoreboard(String contestCode) throws Exception
    {
        scoreboards = getScoreboards();
        if (!scoreboards.containsKey(contestCode))
        {
            try {
                generateScoreboard(contestCode);
            } catch (Exception e) {
                System.out.println("Exception at ContestService.getScoreboard: " + e.getMessage());
                throw e;
            }
        }
        HashMap<String, VOScoreboard> scoreboard = (HashMap<String, VOScoreboard>) scoreboards.get(contestCode);
        Iterator it = scoreboard.keySet().iterator();
        ArrayList<VOScoreboard> ret = new ArrayList<VOScoreboard>();
        
        while (it.hasNext()) 
            ret.add((VOScoreboard) (scoreboard.get((String) it.next())));
        
        Collections.sort(ret);
        return ret;

    }


    private void generateScoreboard(String contestCode)throws Exception
    {
        ss = getSubmissionService();
        scoreboards = getScoreboards();
        try
        {
            scoreboards.put(contestCode, new HashMap<String , VOScoreboard>());
            Contest c = findObject(contestCode);
            List<User> userlist = (List<User>)c.getUserList();
            int nproblems = c.getProblemList().size();
            for(User u: userlist)
                ((HashMap<String , VOScoreboard>)scoreboards.get(contestCode)).put(u.getHandle(), new VOScoreboard(u.getHandle(),nproblems));

        }
        catch (Exception e)
        {
            System.out.println("Exception at ContestService.generateScoreboard: " + e.getMessage());
            throw e;
        }
    }

    public void endContest(String contestCode)
    {
        ss = getSubmissionService();
        ps = getProblemService();
        try
        {
            Contest c = findObject(contestCode);
            List<Problem> problems = c.getProblemList();
            for( Problem p : problems)
            {
                p.setVisible(false);
                ps.updateObject(p);
            }
            updateRating(contestCode);
        }
        catch (Exception e)
        {

        }
    }

    private void updateRating(String contestCode) throws Exception
    {
        ArrayList<VOUser> userlist = us.findAll(EnumSearchParameter.CONTEST, contestCode);

    }

}

